package com.edu.exam.entity.curriculum.questionbank;

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import org.hibernate.annotations.Comment;
import org.hibernate.annotations.SQLDelete;
import org.hibernate.annotations.Where;

import jakarta.persistence.*;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import java.time.LocalDateTime;

/**
 * 版本差异实体类
 * 对应数据库表：version_differences
 *
 * 记录不同版本之间的详细差异信息，支持版本对比和变更内容分析。
 * 提供精确的版本差异追踪功能。
 *
 * @author System
 * @version 1.0.0
 */
@Entity
@Comment("版本差异表")
@SQLDelete(sql = "UPDATE version_differences SET is_deleted = true, delete_time = CURRENT_TIMESTAMP WHERE id = ?")
@Where(clause = "is_deleted = false")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class VersionDifference {

    /**
     * 差异记录唯一标识符
     */
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    /**
     * 源版本ID
     */
    @NotNull(message = "源版本ID不能为空")
    @Column(name = "from_version_id", nullable = false)
    private Long fromVersionId;

    /**
     * 目标版本ID
     */
    @NotNull(message = "目标版本ID不能为空")
    @Column(name = "to_version_id", nullable = false)
    private Long toVersionId;

    /**
     * 差异类型
     */
    @NotNull(message = "差异类型不能为空")
    @Enumerated(EnumType.STRING)
    @Column(name = "diff_type", nullable = false, length = 20)
    private DifferenceType diffType;

    /**
     * 字段名称
     */
    @NotNull(message = "字段名称不能为空")
    @Size(max = 50, message = "字段名称长度不能超过50个字符")
    @Column(name = "field_name", nullable = false, length = 50)
    private String fieldName;

    /**
     * 旧值
     */
    @Column(name = "old_value", columnDefinition = "TEXT")
    private String oldValue;

    /**
     * 新值
     */
    @Column(name = "new_value", columnDefinition = "TEXT")
    private String newValue;

    /**
     * 差异位置，JSON格式
     */
    @Column(name = "diff_position", columnDefinition = "TEXT")
    private String diffPosition;

    /**
     * 差异上下文
     */
    @Column(name = "diff_context", columnDefinition = "TEXT")
    private String diffContext;

    /**
     * 差异级别
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "diff_level", length = 20)
    private DifferenceLevel diffLevel;

    /**
     * 差异描述
     */
    @Size(max = 500, message = "差异描述长度不能超过500个字符")
    @Column(name = "diff_description", length = 500)
    private String diffDescription;

    /**
     * 是否关键字段
     */
    @Column(name = "is_key_field")
    @Builder.Default
    private Boolean isKeyField = false;

    /**
     * 差异权重
     */
    @Column(name = "diff_weight")
    @Builder.Default
    private Integer diffWeight = 1;

    /**
     * 变更影响范围
     */
    @Enumerated(EnumType.STRING)
    @Column(name = "impact_scope", length = 20)
    private ImpactScope impactScope;

    /**
     * 差异元数据，JSON格式
     */
    @Column(name = "metadata", columnDefinition = "TEXT")
    private String metadata;

    /**
     * 记录创建时间
     */
    @Column(name = "create_time", nullable = false, updatable = false)
    private LocalDateTime createTime;

    /**
     * 创建人用户ID
     */
    @Size(max = 50, message = "创建人长度不能超过50个字符")
    @Column(name = "created_by", nullable = false, length = 50)
    private String createdBy;

    /**
     * 乐观锁版本号
     */
    @Version
    @Column(name = "version", nullable = false)
    @Builder.Default
    private Integer version = 1;

    /**
     * 软删除标记
     */
    @Column(name = "is_deleted", nullable = false)
    @Builder.Default
    private Boolean isDeleted = false;

    /**
     * 删除时间
     */
    @Column(name = "delete_time")
    private LocalDateTime deleteTime;

    @PrePersist
    protected void onCreate() {
        LocalDateTime now = LocalDateTime.now();
        this.createTime = now;
    }

    /**
     * 差异类型枚举
     */
    public enum DifferenceType {
        ADD("ADD", "新增"),
        MODIFY("MODIFY", "修改"),
        DELETE("DELETE", "删除"),
        MOVE("MOVE", "移动"),
        COPY("COPY", "复制"),
        FORMAT("FORMAT", "格式变更"),
        STRUCTURE("STRUCTURE", "结构变更");

        private final String code;
        private final String description;

        DifferenceType(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

        public static DifferenceType fromCode(String code) {
            for (DifferenceType type : values()) {
                if (type.getCode().equals(code)) {
                    return type;
                }
            }
            return MODIFY;
        }
    }

    /**
     * 差异级别枚举
     */
    public enum DifferenceLevel {
        MINOR("MINOR", "轻微"),
        NORMAL("NORMAL", "普通"),
        MAJOR("MAJOR", "重要"),
        CRITICAL("CRITICAL", "关键");

        private final String code;
        private final String description;

        DifferenceLevel(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

        public static DifferenceLevel fromCode(String code) {
            for (DifferenceLevel level : values()) {
                if (level.getCode().equals(code)) {
                    return level;
                }
            }
            return NORMAL;
        }
    }

    /**
     * 影响范围枚举
     */
    public enum ImpactScope {
        LOCAL("LOCAL", "局部"),
        MODULE("MODULE", "模块"),
        SYSTEM("SYSTEM", "系统"),
        GLOBAL("GLOBAL", "全局");

        private final String code;
        private final String description;

        ImpactScope(String code, String description) {
            this.code = code;
            this.description = description;
        }

        public String getCode() {
            return code;
        }

        public String getDescription() {
            return description;
        }

        public static ImpactScope fromCode(String code) {
            for (ImpactScope scope : values()) {
                if (scope.getCode().equals(code)) {
                    return scope;
                }
            }
            return LOCAL;
        }
    }

}